package repository

import (
	"errors"
	"fmt"
	"invitation/internal/model"
	"invitation/internal/repository/cache"

	"gorm.io/gorm"
)

type FirstTimePostportRepository interface {
	Create(teacherInfoID uint, postportUrl string) error
	Update(teacherInfoID uint, postportUrl string) error
	Delete(teacherInfoID uint) error
	FindOneByTeacherInfoID(teacherInfoID uint) (*model.FirstTimePostport, error)
}

type firstTimePostportRepository struct {
	*BaseRepository
}

func newFirstTimePostportRepository(db *gorm.DB) *firstTimePostportRepository {
	return &firstTimePostportRepository{
		BaseRepository: newBaseRepository(db),
	}
}

func (ftpr *firstTimePostportRepository) Create(teacherInfoID uint, postportUrl string) error {
	postport := &model.FirstTimePostport{
		FirstTimeTeacherInfoID: teacherInfoID,
		PostportUrl:            postportUrl,
	}
	return ftpr.GetDB().Create(postport).Error
}

func (ftpr *firstTimePostportRepository) Update(teacherInfoID uint, postportUrl string) error {
	// 1. 获取旧数据，用于判断记录是否存在
	var oldPostport model.FirstTimePostport
	if err := ftpr.GetDB().Where("first_time_teacher_info_id = ?", teacherInfoID).First(&oldPostport).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return fmt.Errorf("postport with first_time_teacher_info_id %d not found, cannot update", teacherInfoID)
		}
		return err
	}

	// 2. 构建更新 Map
	updateData := make(map[string]interface{})
	if postportUrl != "" {
		updateData["postport_url"] = postportUrl
	}

	// 3. 执行更新
	if len(updateData) == 0 {
		return nil
	}

	return ftpr.GetDB().Model(&oldPostport).Updates(updateData).Error
}

func (ftpr *firstTimePostportRepository) Delete(teacherInfoID uint) error {
	return ftpr.GetDB().Where("first_time_teacher_info_id = ?", teacherInfoID).Delete(&model.FirstTimePostport{}).Error
}

func (ftpr *firstTimePostportRepository) FindOneByTeacherInfoID(teacherInfoID uint) (*model.FirstTimePostport, error) {
	var postport model.FirstTimePostport
	err := ftpr.GetDB().Where("first_time_teacher_info_id = ?", teacherInfoID).First(&postport).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, fmt.Errorf("postport not found for first_time_teacher_info_id: %d", teacherInfoID)
		}
		return nil, err
	}
	return &postport, nil
}

// 缓存版本
type cachedFirstTimePostportRepository struct {
	*BaseCachedRepository
}

func newCachedFirstTimePostportRepository(db *gorm.DB, cache *cache.LRU, repoName string) *cachedFirstTimePostportRepository {
	repo := newFirstTimePostportRepository(db)
	return &cachedFirstTimePostportRepository{
		BaseCachedRepository: newBaseCachedRepository(repo, cache, repoName),
	}
}

func (cftpr *cachedFirstTimePostportRepository) BaseRepo() *firstTimePostportRepository {
	return cftpr.GetBaseRepo().(*firstTimePostportRepository)
}

var postportTeacherInfoIDKey = "postport_teacher_info_id"

func (cftpr *cachedFirstTimePostportRepository) Create(teacherInfoID uint, postportUrl string) error {
	cftpr.mutex.Lock()
	defer cftpr.mutex.Unlock()

	if cftpr.GetCache() == nil {
		return cftpr.BaseRepo().Create(teacherInfoID, postportUrl)
	}

	cacheKey := cftpr.GenerateCacheKey(postportTeacherInfoIDKey, teacherInfoID)
	cftpr.GetCache().Remove(cacheKey)
	return cftpr.BaseRepo().Create(teacherInfoID, postportUrl)
}

func (cftpr *cachedFirstTimePostportRepository) Update(teacherInfoID uint, postportUrl string) error {
	cftpr.mutex.Lock()
	defer cftpr.mutex.Unlock()

	err := cftpr.BaseRepo().Update(teacherInfoID, postportUrl)
	if err != nil {
		return err
	}

	if cftpr.GetCache() == nil {
		return nil
	}

	cacheKey := cftpr.GenerateCacheKey(postportTeacherInfoIDKey, teacherInfoID)
	cftpr.GetCache().Remove(cacheKey)
	return nil
}

func (cftpr *cachedFirstTimePostportRepository) Delete(teacherInfoID uint) error {
	cftpr.mutex.Lock()
	defer cftpr.mutex.Unlock()

	if cftpr.GetCache() == nil {
		return cftpr.BaseRepo().Delete(teacherInfoID)
	}

	cacheKey := cftpr.GenerateCacheKey(postportTeacherInfoIDKey, teacherInfoID)
	cftpr.GetCache().Remove(cacheKey)
	return cftpr.BaseRepo().Delete(teacherInfoID)
}

func (cftpr *cachedFirstTimePostportRepository) FindOneByTeacherInfoID(teacherInfoID uint) (*model.FirstTimePostport, error) {
	cftpr.mutex.Lock()
	defer cftpr.mutex.Unlock()

	if cftpr.GetCache() == nil {
		return cftpr.BaseRepo().FindOneByTeacherInfoID(teacherInfoID)
	}

	cacheKey := cftpr.GenerateCacheKey(postportTeacherInfoIDKey, teacherInfoID)
	if value, ok := cftpr.GetCache().Get(cacheKey); ok {
		return value.(*model.FirstTimePostport), nil
	}

	postport, err := cftpr.BaseRepo().FindOneByTeacherInfoID(teacherInfoID)
	if err != nil {
		return nil, err
	}

	cftpr.GetCache().Add(cacheKey, postport)
	return postport, nil
}

func NewFirstTimePostportRepositoryWithCache(db *gorm.DB, cache *cache.LRU, repoName string) Repository {
	return newCachedFirstTimePostportRepository(db, cache, repoName)
}
